import {
  Directive,
  Input,
  OnInit,
  OnDestroy,
  AfterViewInit,
  HostBinding,
  HostListener,
  ElementRef,
  Renderer2,
  Output,
  EventEmitter,
} from '@angular/core';
import { CdkOverlayOrigin } from '@angular/cdk/overlay';

import { DropdownComponent } from './dropdown.component';

@Directive({
  selector: '[fuiDropdownTrigger]',
})
export class DropdownTriggerDirective implements OnInit, OnDestroy, AfterViewInit {
  @HostBinding('class.fui-dropdown-trigger') hostClass = true;

  @HostBinding('class.fui-dropdown-open') dropdownOpenClass;

  /** Dropdown component to be triggered by this element. */
  @Input('fuiDropdownTrigger') dropdown: DropdownComponent;

  /** Emit dropdown visibility. */
  @Output() fuiDropdownVisible = new EventEmitter<boolean>();

  documentListeners = [];

  constructor(
    public elementRef: ElementRef,
    public renderer: Renderer2,
  ) { }

  ngOnInit() {
    this.dropdown.setOverlayOrigin(this);

    this.dropdown.visible
    .subscribe((visible) => {
      this.dropdownOpenClass = visible;
      this.fuiDropdownVisible.emit(visible);
    });
  }

  ngAfterViewInit() {
    if (this.dropdown.trigger === 'hover') {
      this.renderer.listen(this.elementRef.nativeElement, 'mouseenter', () => this.show());
    } else if (this.dropdown.trigger === 'click') {
      this.renderer.listen(this.elementRef.nativeElement, 'click', (e) => {
        e.preventDefault();
        this.show();
      });
    } else if (this.dropdown.trigger === 'context') {
      this.renderer.addClass(this.elementRef.nativeElement, 'fui-dropdown-origin-container');
      this.renderer.listen(this.elementRef.nativeElement, 'contextmenu', (e: MouseEvent) => {
        e.preventDefault();
        this._displayContextMenu(e);
      });

      // hide on any relavent event
      ['click', 'contextmenu', 'scroll'].forEach((event: any) => {
        const listener = this.renderer.listen(document, event, () => {
          this.dropdown.hide();
        });
        this.documentListeners.push(listener);
      });
    }
  }

  ngOnDestroy() {
    this.documentListeners.forEach((listener) => {
      listener();
    });
  }

  show() {
    if (this.dropdown.open !== false) {
      this.dropdown.show();
    }
  }

  private _displayContextMenu(event: MouseEvent) {
    const hostRect = this.elementRef.nativeElement.getBoundingClientRect();
    const dropdownOriginElement = document.createElement('span');
    this.renderer.setStyle(dropdownOriginElement, 'position', 'absolute');
    this.renderer.setStyle(dropdownOriginElement, 'top', event.clientY - hostRect.top + 'px');
    this.renderer.setStyle(dropdownOriginElement, 'left', event.clientX - hostRect.left + 'px');
    this.renderer.appendChild(this.elementRef.nativeElement, dropdownOriginElement);

    const dropdownOrigin = new CdkOverlayOrigin(new ElementRef(dropdownOriginElement));
    this.dropdown.setOverlayOrigin(dropdownOrigin);

    setTimeout(() => {
      this.dropdown.show();
      setTimeout(() => { // destroy this temporary origin
        this.renderer.removeChild(this.elementRef.nativeElement, dropdownOriginElement);
      });
    });
  }

}
